#pragma once
#include <string>
#include "../common/message.hpp"
#include "../common/net.hpp"

namespace rpc
{
    namespace server
    {
        // Json::value里的类型
        enum v_type
        {
            BOOL = 0,
            INT,
            ARRAY,
            OBJECT,
            NULLPOINT,
            STRING
        };

        // 服务端描述窗口
        class ServiceDescribe
        {
        public:
            using ptr = std::shared_ptr<ServiceDescribe>;
            using pair_type = std::pair<std::string, v_type>;
            using Callback_Describe = std::function<void(const Json::Value &, Json::Value &)>;

            // 构造函数
            ServiceDescribe(const std::string &mname, Callback_Describe &&callback, std::vector<pair_type> &&params, v_type rtype)
                : _method_name(mname),
                  _describeCallback(std::move(callback)),
                  _params(std::move(params)),
                  _return_type(rtype)
            {
            }

            // 提供参数校验方法
            bool checkParams(const Json::Value &params)
            {
                for (auto desc : _params)
                {
                    if (params.isMember(desc.first) == false)
                    {
                        errlog("参数方法错误");
                        return false;
                    }

                    if (check(desc.second, params[desc.first]) == false)
                    {
                        errlog("参数类型错误:%s", desc.first.c_str());
                        return false;
                    }
                }

                return true;
            }

            // 对回调函数进行校验
            bool Callback(const Json::Value &params, Json::Value &result)
            {
                // 得到一个回调后的结果
                _describeCallback(params, result);
                // 对结果的返回值进行校验
                if (checkRtype(result) == false)
                {
                    errlog("回调函数类型错误");
                    return false;
                }
                return true;
            }

            std::string getMethodName()
            {
                return _method_name;
            }

        private:
            // 校验参数类型
            bool check(v_type &vtype, const Json::Value &val)
            {
                switch (vtype)
                {
                case v_type::BOOL:
                    return val.isBool();
                case v_type::INT:
                    return val.isInt();
                case v_type::OBJECT:
                    return val.isObject();
                case v_type::ARRAY:
                    return val.isArray();
                case v_type::STRING:
                    return val.isString();
                }

                errlog("参数类型错误");
                return false;
            }

            // 检查返回值:检查返回类型和val里面的类型是否是相同的
            bool checkRtype(const Json::Value &val)
            {
                return check(_return_type, val);
            }

        private:
            std::string _method_name;            // 方法名称
            Callback_Describe _describeCallback; // 实际业务处理函数,传入两个Json::value对象？
            std::vector<pair_type> _params;      // 参数描述字段
            v_type _return_type;                 // 返回参数类型
        };

        // 因为要修改类内的成员变量，所以为了安全性可以搭建一个简单的建造者模式
        class DescribeFactory
        {
        public:
            // 设置方法名
            void setMethod(const std::string &mname)
            {
                _method_name = mname;
            }
            // 设置回调
            void setCallback(const ServiceDescribe::Callback_Describe &callback)
            {
                _describeCallback = callback;
            }
            // 设置参数
            void PushParam(const std::string &pname, const v_type &vtype)
            {
                _params.push_back(ServiceDescribe::pair_type(pname, vtype));
            }
            // 设置返回值
            void setRtype(const v_type &rtype)
            {
                _return_type = rtype;
            }

            // 简单的建造者模式
            ServiceDescribe::ptr build()
            {
                return std::make_shared<ServiceDescribe>(_method_name,
                                                         std::move(_describeCallback), std::move(_params),
                                                         _return_type);
            }

        private:
            std::string _method_name;                             // 方法名称
            ServiceDescribe::Callback_Describe _describeCallback; // 实际业务处理函数,传入两个Json::value对象？
            std::vector<ServiceDescribe::pair_type> _params;      // 参数描述字段
            v_type _return_type;                                  // 返回参数类型
        };

        // 对Describe进行管理
        class routerManager
        {
        public:
            // 增删查
            using ptr = std::shared_ptr<routerManager>;
            void insert(const ServiceDescribe::ptr &desc)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                // 要往_services里面添加
                std::string method_name = desc->getMethodName();
                _services.insert(std::make_pair(method_name, desc));
            };
            void remove(const std::string &mname)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(mname);
                if (it == _services.end())
                {
                    errlog("服务不存在");
                    return;
                }
                _services.erase(it);
            };
            ServiceDescribe::ptr select(std::string mname)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _services.find(mname);
                if (it == _services.end())
                {
                    errlog("服务不存在");
                    return ServiceDescribe::ptr();
                }
                return it->second;
            };

        private:
            std::mutex _mutex; // 添加一个互斥锁
            std::unordered_map<std::string, const ServiceDescribe::ptr> _services;
        };

        class rpcRouter
        {
        public:
            using ptr = std::shared_ptr<rpcRouter>;
            rpcRouter() : _service_manager(std::make_shared<routerManager>()) {}
            void onRpcRequest(const BaseConnection::ptr &conn, RpcRequest::ptr &request) // 提供给Describe模块的Request注册方法
            {
                // 查询客户端发送的请求方法
                auto it = _service_manager->select(request->getMethod());
                if (it.get() == nullptr)
                {
                    errlog("%s:服务未找到", request->getMethod().c_str());
                    Json::Value val;
                    return response(conn, request, val, MY_CODE::RCODE_NOT_FOUND_SERVICE);
                }
                // 校验参数
                if (it->checkParams(request->getParams()) == false)
                {
                    errlog("%s:参数校验失败", request->getMethod().c_str());
                    Json::Value val;
                    return response(conn, request, val, MY_CODE::RCODE_INVAILED_PARAMS);
                }
                // 调用业务回调处理请求
                Json::Value res;
                bool ret = it->Callback(request->getParams(), res);
                if (ret == false)
                {
                    errlog("%s:回调函数调用失败", request->getMethod().c_str());
                    Json::Value val;
                    // 服务器内部错误
                    return response(conn, request, val, MY_CODE::RCODE_INTERNAL_ERR);
                }
                // 得到结果，组织响应，发送给客户端
                return response(conn, request, res, MY_CODE::RCODE_OK);
            }
            // 方法注册函数:方法名称，参数,handeller函数：使用工厂类生产
            void RegisterMethod(const ServiceDescribe::ptr &service)
            {
                return _service_manager->insert(service);
            }

        private:
            void response(const BaseConnection::ptr &conn,
                          const RpcRequest::ptr &req,
                          Json::Value &res,
                          MY_CODE code)
            {
                auto msg = MessageFactory::create(rpc::MY_TYPE::RSP_RPC);
                auto rsp = std::dynamic_pointer_cast<RpcResponse>(msg);
                rsp->setId(req->getId());
                rsp->setMytype(MY_TYPE::RSP_RPC);
                rsp->setRecode(code);
                rsp->setResult(res);
                conn->send(rsp);
            }
            routerManager::ptr _service_manager; // 描述管理成员
        };

    }
}